/*******************************************************************************

                  LVGL 输入法之符号输入法实现
键盘图标用于进入选择输入法界面,键值LV_KEY_HOME
LOOP图标用于顺序切换输入法，键值LV_KEY_END
LIST图标用于选择符号组，键值LV_KEY_PREV
*******************************************************************************/
#include "lvIME_Base.h"
#include <string.h>

extern const char *lvIME_cbGetSignDefault(void);//获得默认表

//----------------------------------11x3模式键盘布局定义-------------------------
//默认映射表,每个页最多25个,三排按10,8,7排列
//动态映射表：
static const char * BTNMAP_CONST _KbBtnMap[] =
  {lvIME_SignBuf[0], lvIME_SignBuf[1], lvIME_SignBuf[2], lvIME_SignBuf[3], lvIME_SignBuf[4], lvIME_SignBuf[5], lvIME_SignBuf[6], lvIME_SignBuf[7], lvIME_SignBuf[8], lvIME_SignBuf[9],LV_SYMBOL_BACKSPACE,"\n",
  LV_SYMBOL_KEYBOARD, lvIME_SignBuf[10], lvIME_SignBuf[11], lvIME_SignBuf[12], lvIME_SignBuf[13], lvIME_SignBuf[14], lvIME_SignBuf[15],lvIME_SignBuf[16], lvIME_SignBuf[17], LV_SYMBOL_NEXT, LV_SYMBOL_LIST, LV_SYMBOL_CLOSE,"\n",
  LV_SYMBOL_LOOP, LV_SYMBOL_LEFT, lvIME_SignBuf[18], lvIME_SignBuf[19], lvIME_SignBuf[20], lvIME_SignBuf[21], lvIME_SignBuf[22], lvIME_SignBuf[23], lvIME_SignBuf[24], LV_SYMBOL_RIGHT,  LV_SYMBOL_OK, ""};

//位置转键值,与_KbBtnMap对应
static const signed char _KbPos2Key[] = {
  'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', LV_KEY_BACKSPACE,
  LV_KEY_HOME, 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', LV_KEY_NEXT, LV_KEY_PREV, LV_KEY_ESC,
  LV_KEY_END, LV_KEY_LEFT,'s', 't', 'u', 'v', 'w', 'x', 'y', LV_KEY_RIGHT, LV_KEY_ENTER};

//25个符号在键盘中的位置查找表
static const unsigned char _KbPos2MapId[] = {
  0,1,2,3,4,5,6,7,8,9,
  12,13,14,15,16,17,18,19,
  25,26,27,28,29,30,31};

//键盘布局控制：
const lv_buttonmatrix_ctrl_t lvIME_KbSignCtrlMap[] =
  {0,  0, 0, 0, 0, 0, 0, 0, 0, 0,  0,
   8,  10,10,10,10,10,10,10,10,7,7,8,
   8,  8,10,10,10,10,10,10,10,10, 14};

struct _lvIME_Sign{
  const char *pSignTbl;       //缓存的用户符号表
  const char *pCurSignTbl;    //当前页符号表
  const char *pNextSignTbl;   //下页符号表
  unsigned short SignCount;   //符号总数
  signed char CurPage;        //当前页码
};

static unsigned char _CurKbType; //当前键盘类型
struct _lvIME_Sign lvIME_Sign[2]; //固定符号与用户符号分别管理


//----------------------------更新符号-----------------------------------
//符号表变化后调用
void lvIME_UpdateSign(lv_obj_t *pBtnM,    //NULL时为初始化
                     const char *pSignTbl)//用户符号表,NULL为默认
{
  if(pSignTbl == NULL){//默认表
    _CurKbType = 0;
    pSignTbl = lvIME_cbGetSignDefault();
    if(lvIME_Sign[0].pSignTbl != pSignTbl){//首次使用初始化
      lvIME_Sign[0].pSignTbl = pSignTbl;
      lvIME_Sign[0].pCurSignTbl = pSignTbl;
      lvIME_Sign[0].SignCount = lvIME_GetSignTblCount(pSignTbl);
      lvIME_Sign[0].CurPage = -1; //NEXT时到0
      lvIME_ClrSignBuf(lvIME_SignBuf[0], 0 ,25); //初始化符号表
    }
    else lvIME_Sign[0].CurPage--;//NEXT时到当前页
    lvIME_Sign[0].pNextSignTbl = lvIME_Sign[0].pCurSignTbl;//恢复为当前
  }
  else{//用户表
    _CurKbType = 1;
    if(lvIME_Sign[1].pSignTbl != pSignTbl){//首次使用初始化
      lvIME_Sign[1].pSignTbl = pSignTbl;
      lvIME_Sign[1].pCurSignTbl = pSignTbl;
      lvIME_Sign[1].SignCount = lvIME_GetSignTblCount(pSignTbl);
      lvIME_Sign[1].CurPage = -1; //NEXT时到0
      lvIME_ClrSignBuf(lvIME_SignBuf[0], 0, 25); //初始化符号表
    }
    else lvIME_Sign[1].CurPage--;//NEXT时到当前页
    lvIME_Sign[1].pNextSignTbl = lvIME_Sign[1].pCurSignTbl;//恢复为当前
  }
  //更新符号
  if(pBtnM != NULL) lvIME_ToNextSign(pBtnM);
}

//---------------------------------创建符号输入法----------------------------
//返回创建的对像
lv_obj_t *lvIME_CreateSign(lv_event_cb_t _cbEventHandler, //回调函数
                          void *pv,//回调函数带的参数
                          const char *pSignTbl)//用户符号表,NULL为默认
{
  //初始化结构
  lvIME_UpdateSign(NULL, pSignTbl);
  //创建横向铺满的键盘
  lv_obj_t * pBtnM = lvIME_CreateKeyStart(_cbEventHandler, pv);
  lv_obj_set_size(pBtnM, lv_pct(100), LV_IME_KB_ROW_HIGHT * 3);
  lv_buttonmatrix_set_map(pBtnM, (const char **)_KbBtnMap); //首次也需要更新，否则Map总数不对！
  lvIME_ToNextSign(pBtnM); //更新符号
  return pBtnM;
}

//-----------------------------到下一页符号---------------------------
//lvIME_GetKeySign为LV_SYMBOL_NEXT时，调用本函数循环切换符号
void lvIME_ToNextSign(lv_obj_t *pBtnM) //lv_buttonmatrix对像
{
  struct _lvIME_Sign *pIME = &lvIME_Sign[_CurKbType];
  //先切下一页
  const char * pSignTbl;
  pIME->CurPage++;
  unsigned short SignBase = pIME->CurPage * 25;
  if(SignBase >= pIME->SignCount){//回环了
    pIME->CurPage = 0;
    SignBase = 0;
    pSignTbl = pIME->pSignTbl;
    pIME->pNextSignTbl = pSignTbl; //复位
  }
  else pSignTbl = pIME->pNextSignTbl;
  pIME->pCurSignTbl = pSignTbl;
  //本页结束位置与填充空总数
  unsigned short SignCount = SignBase + 25;
  if(SignCount > pIME->SignCount) //本页为最后一页
    SignCount = 25 - (SignCount - pIME->SignCount);
  else SignCount = 25; //一页装满了
  //更新按键上的符号
  pIME->pNextSignTbl = lvIME_SignTblToBuf(lvIME_SignBuf[0],
                                          SignCount, pSignTbl);
  lvIME_ClrSignBuf(lvIME_SignBuf[0], SignCount, 25); //无用键清除

  lv_buttonmatrix_set_map(pBtnM, (const char **)_KbBtnMap); //刷新前须更新，否则会程序异常
  lv_buttonmatrix_set_ctrl_map(pBtnM, lvIME_KbSignCtrlMap);
  //更新禁止符号
  for(unsigned char i = 0; i  < 25;  i++){//set_map后才能生效！
    if(i < SignCount)
      lv_buttonmatrix_clear_button_ctrl(pBtnM, _KbPos2MapId[i], LV_BUTTONMATRIX_CTRL_DISABLED);
    else
      lv_buttonmatrix_set_button_ctrl(pBtnM, _KbPos2MapId[i], LV_BUTTONMATRIX_CTRL_DISABLED);
  }
  lv_obj_update_layout(pBtnM); //强制更新布局以使大小生效
}

//-----------------------------得到符号输入键值---------------------------
//符号位置按由上到下，由左到右排列，对应键值为 'a'-'y',收到
unsigned char lvIME_GetKeySign(lv_obj_t *pBtnM) //lv_buttonmatrix对像
{
  unsigned char KeyId = lv_btnmatrix_get_selected_btn(pBtnM);
  return _KbPos2Key[KeyId];
}

//-----------------------------得到当前输入的符号---------------------------
//lvIME_GetKeySign()键值为 'a'-'y'时调用
const char *lvIME_pGetSign(lv_obj_t *pBtnM, unsigned char KeySign)
{
  //if((KeySign < 'a') || (KeySign > 'y')) return NULL; //异常调用
  return lvIME_SignBuf[KeySign - 'a'];
}
